
(function () {


  //临时用
  let ps: any, hook: any, _isHeroOk, _isTouchEnabled, Global, EventManager, UIManager, FightManager, Fight_State;

  let _globalObsList = [];

  function NewObs() {
    let _name; //名称
    let _paused = false;//暂停
    let _resumeCallback; //继续回调
    let _stoped = true;//停止
    let _end = false;//结束
    let _pos = 0; //当前 pipe 位置
    const _obsList = []; // pipe 队列
    let _obsResList = []; // pipe 结果队列， 处理结束、停止和暂停时机 { async start(){},  async end(){}, async stop(){}, async pause(){}}
    //是否可以 done
    const _canDone = function () {
      return !(_stoped || _end || _paused);
    };
    let _donePromise;
    //处理 _obsList
    const _done = async function () {
      if (!_canDone()) return;
      for (let len = _obsList.length; _pos < len; _pos++) {
        let item = _obsList[_pos];
        let res;
        if (item && item.fn) res = await item.fn.call(_obs, _obs);
        if (!_canDone()) break;
        if (res) {
          _obsResList.push(res);
          res.start && await res.start();
        }
      }
      if (_pos >= _obsList.length) {
        await _doneRes('end');
        _end = true;
      };
      if (_donePromise) {
        _donePromise();
        _donePromise = null;
      }
    };
    const _doneRes = async function (type) {
      for (let i = 0, len = _obsResList.length; i < len; i++) {
        const item = _obsResList[i];
        item[type] && await item[type]();
      }
      if (type == 'end') _obsResList = [];
    };
    const _obs = {
      get isEnd() { return _end; },
      get isPaused() { return _paused; },
      get isStoped() { return _stoped; },
      canDone() { return _canDone(); },
      /** 设置名称，如果有值，可给别的obs获得，设置空值时可以从globalObsList删除 */
      name(n) {
        if (n == _name) return this;
        //删除旧的
        if (_name) {
          _globalObsList = _globalObsList.filter(function (item) { item.name != _name; });
        }
        if (_end) return this;
        //添加到_globalObsList
        if (n) {
          _globalObsList.push({ obs: _obs, name: n });
        }
        _name = n;
        return this;
      },
      /** 获取obs */
      getObs(name) {
        return _globalObsList.find(function (item) { return item.name == name; });
      },
      /** 添加流, pipe(fn) || pipe(name, fn) */
      pipe(p1, p2) {
        const hasName = typeof ('') == typeof (p1);
        const name = hasName ? p1 : null;
        const fn = hasName ? p2 : p1;
        if (_end) return this;
        _obsList.push({ fn, name });
        return this;
      },
      /** 跳转到pos */
      gotoPos(n) {
        if (_end) return this;
        _pos = n;
        return this;
      },
      goto(name) {
        if (_end) return this;
        const index = _obsList.findIndex(function (item) { return item.name == name; });
        if (index >= 0) _pos = index;
        return this;
      },
      /** 等待(sm微秒)，返回false表示停止或结束*/
      async wait(s) {
        //如果停止返回false
        return new Promise(function (r) {
          if (!_canDone()) return r(false);
          setTimeout(function () {
            r(_canDone());
          }, s || 1);
        });
      },
      async waitEx(where, timeout) {
        //如果停止返回false
        return new Promise(function (r) {
          if (!_canDone()) return r(false);
          const iId = setInterval(function () {
            if (where && where()) {
              endFn();
              r(_canDone());
            }
          }, 20);
          const tId = setTimeout(function () {
            endFn();
            r(_canDone());
          }, timeout || 1);
          const endFn = function () {
            clearInterval(iId);
            clearTimeout(tId);
          };
        });
      },
      /** 暂停，返回false表示停止或结束 */
      async pause() {
        if (_paused) return;
        _paused = true;
        _obs.moveStop();
        await _doneRes('pause');
        //如果停止返回false
        return new Promise(function (r) {
          if (_stoped || _end) return r(false);
          _resumeCallback = function () {
            return r(!(_stoped || _end));
          };
        });
      },
      /** 继续 */
      async resume() {
        if (!_paused) return;
        _paused = false;
        await _doneRes('resume');
        _resumeCallback && _resumeCallback();
        _resumeCallback = null;
        return this;
      },
      /** 停止 */
      async stop() {
        if (!_stoped) return this;
        _stoped = true;
        _obs.moveStop();
        await new Promise(function (r) {
          _donePromise = function () {
            r(true);
          };
        });
        await _doneRes('stop');
        return this;
      },
      /** 开始或重新开始 */
      async start() {
        await this.end();
        if (_canDone()) return;
        _stoped = _paused = _end = false;
        _pos = 0;
        await _done();
        return this;
      },
      /** 结束 */
      async end() {
        if (_end) return this;
        if (!_stoped) await _obs.stop();
        if (_paused) await _obs.resume();
        _end = true;
        await _doneRes('end');
        return this;
      },
      //以下是辅助方法
      moveElement(element, force) {
        if (!_canDone()) return;
        return ps.link.goToElement.apply(ps.link, arguments);
      },
      move(gridX, gridY, element, force) {
        if (!_canDone()) return;
        return ps.link.go.apply(ps.link, arguments);
      },
      //var element = obs.moveFirst(function (mapType, element) { return isFuwen(mapType, element); });
      moveFirst(checkFn, distance) {
        if (!_canDone()) return;
        return ps.ui.map.goToFirst.apply(ps.ui.map, arguments);
      },
      findFirst(checkFn, distance) {
        return ps.ui.map.findFirst.apply(ps.ui.map, arguments)
      },
      moveStop() {
        ps && ps.link && ps.link.stop(true);
      },
      exit(force) {
        if (!_canDone()) return;
        return ps.ui.map.exit(force);;
      },
      //await hook('PvpHandler.GC_MEET_QUERY', 'Msg.CG_MEET_QUERY')();
      hook(msg, endMsg) {
        return hook.apply(this, arguments);
      },
      isBanFu(mapType, element) {
        return mapType == 2 && element.bodyID == 1058;
      },
      //返回false结束
      async waitHeroOk() {
        await _obs.waitEx(function () {
          return _isHeroOk() && _isTouchEnabled();
        }, 500);
        return _canDone();
      },
      isHeroOk() {
        return _isTouchEnabled() && Global.hero.route == null && FightManager.fightState == Fight_State.Normal && Global.hero.behavior == 0;
      },
      isTouchEnabled() {
        return !(!EventManager.touchEnabled || UIManager.guide && !UIManager.guide.touchEnabled)
      },
      isHeroEffect() {
        return Global.hero.effectList && Global.hero.effectList.buffer;
      }
    };

    return _obs;
  }

  function _equalLogs(logs1, logs2) {
    if (!logs1 || !logs2) return logs1 === logs2;
    if (logs1.length != logs2.length) return false;
    let eq = true;
    logs1.forEach(function (item, index) {
      if (eq) eq = (item == logs2[index]);
    });
    return eq;
  };

  (function () {
    let logs = [];
    NewObs().name('testEnd').pipe(function (obs) {

      return {
        start() {
          logs.push('start 1');
        },
        end() {
          logs.push('end 1');
          console.log('testEnd ok: ', _equalLogs(logs, ["start 1", "1111", "end 1"]));
          console.log('testEnd', logs);
        }
      };
    }).pipe('aa', async function (obs) {
      logs.push('1111');
      setTimeout(async () => {
        await obs.end();
        logs.push('end 2');
      }, 1);
      if (!await obs.wait(2000)) return;
      logs.push('2222');

    }).pipe(async function (obs) {
      logs.push('3333');

    }).start();

  })();

  (function () {
    let logs = [];
    NewObs().name('testPause').pipe(function (obs) {
      return {
        start() {
          logs.push('start 1');
        },
        pause() {
          logs.push('pause 1');
        },
        resume() {
          logs.push('resume 1');
        },
        stop() {
          logs.push('stop 1');
        },
        end() {
          logs.push('end 1');
          console.log('testPause ok: ', _equalLogs(logs, ["start 1", "1111", "pause 1", "resume 1", "resume 2", "pause resume", "2222", "3333", "end 1"]));
          console.log('testPause', logs);
        }
      };
    }).pipe('aa', async function (obs) {
      logs.push('1111');
      setTimeout(async () => {
        await obs.resume();
        logs.push('resume 2');
      }, 1000);
      if (!await obs.pause()) return;
      logs.push('pause resume');
      logs.push('2222');

    }).pipe(async function (obs) {
      logs.push('3333');

    }).start();

  })();

  (function () {
    let logs = [];
    let started = false;
    let end = false;
    NewObs().name('testStart').pipe(function (obs) {
      return {
        start() {
          logs.push('start 1');
        },
        pause() {
          logs.push('pause 1');
        },
        resume() {
          logs.push('resume 1');
        },
        stop() {
          logs.push('stop 1');
        },
        end() {
          logs.push('end 1');
        }
      };
    }).pipe('aa', async function (obs) {
      logs.push('1111');
      if (!started) {
        started = true;
        setTimeout(async () => {
          await obs.start();
          logs.push('start 2');
          console.log('testStart ok: ', _equalLogs(logs, ["start 1", "1111", "pause 1", "resume 1", "end 1", "pause resume", "start 1", "1111", "2222", "3333", "end 1", "start 2"]));
          console.log('testStart', logs);

        }, 1000);
        if (!await obs.pause()) return;
        logs.push('pause resume');
        return;
      }
      logs.push('2222');

    }).pipe(async function (obs) {
      logs.push('3333');

    }).start();

  })();



})();
